package com.sangeng.service.serviceimpl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sangeng.domain.ResponseResult;
import com.sangeng.domain.dto.UserDto;
import com.sangeng.domain.entity.User;
import com.sangeng.domain.vo.UserInfoVo;
import com.sangeng.enums.AppHttpCodeEnum;
import com.sangeng.exception.SystemException;
import com.sangeng.mapper.UserMapper;
import com.sangeng.service.UserService;
import com.sangeng.utils.BeanCopyUtils;
import com.sangeng.utils.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

/**
 * 用户表(User)表服务实现类
 *
 * @author makejava
 * @since 2022-08-16 18:57:15
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    public ResponseResult<UserInfoVo> userInfo() {
        //获取用户id
        //利用SecurityContextHolder获取用户对象然后获取用户id
        Long userId = SecurityUtils.getUserId();
        //根据用户id查询用户信息
        User user = getById(userId);
        //将用户信息封装成UserInfoVo
        UserInfoVo userInfoVo = BeanCopyUtils.copyBean(user, UserInfoVo.class);
        return ResponseResult.okResult(userInfoVo);
    }

    @Override
    public ResponseResult<String> updateUserInfo(User user) {
        updateById(user);//实际上这一行代码是有安全问题的，可能有人利用前端接口发一些我们不需要的字段，我们应该只更新我们想要更新的字段，比如密码..
        //留坑 update(update Wrapper) 利用这个可以设置我们只想更新的字段
        return ResponseResult.okResult();
    }

    private final PasswordEncoder passwordEncoder;
    @Override
    public ResponseResult<String> register(UserDto userDto) {
        //对请求体传过来的用户信息进行判空
        //为什么后端也要加校验？不直接在前端已经完成了吗？ 不！可能会有人利用工具发送http请求 而不是在前端输入
        //留个坑 可以用 Spring Validation做校验 就没有那么多if语句 看起来爽
        /**
         * 下面的代码改为在Controller上加@Validated注解 和 UserDto中使用@NotBlank 来校验值是否为空，
         * 记住要用NotBlank而不是Notnull 否则""空字符串会通过校验
        if (!StringUtils.hasText(user.getUserName())) {
            throw new SystemException(AppHttpCodeEnum.USERNAME_NOT_NULL);
        }
        if (!StringUtils.hasText(user.getEmail())) {
            throw new SystemException(AppHttpCodeEnum.EMAIL_NOT_NULL);
        }
        if (!StringUtils.hasText(user.getPassword())) {
            throw new SystemException(AppHttpCodeEnum.PASSWORD_NOT_NULL);
        }
        if (!StringUtils.hasText(user.getNickName())) {
            throw new SystemException(AppHttpCodeEnum.NICKNAME_NOT_NULL);
        }*/

        //不为空 则对数据进行判重（是否存在已经注册的邮箱等）
        if(emailExist(userDto.getNickName())){
            throw new SystemException(AppHttpCodeEnum.EMAIL_EXIST);
        }
        if(userNameExist(userDto.getUserName())){
            throw new SystemException(AppHttpCodeEnum.USERNAME_EXIST);
        }
        if(nickNameExist(userDto.getNickName())){
            throw new SystemException(AppHttpCodeEnum.NICKNAME_EXIST);
        }
        //对密码加密加盐存入数据库 SecurityConfig已经制定了解密的算法 所以我们加密得用同样的
        String encodePassword = passwordEncoder.encode(userDto.getPassword());
        userDto.setPassword(encodePassword);
        //存入数据库
        User user = BeanCopyUtils.copyBean(userDto, User.class);
        save(user);
        return ResponseResult.okResult();
    }

    private boolean userNameExist(String userName) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName, userName);
        return count(queryWrapper) > 0;//相当于select count
    }

    private boolean nickNameExist(String nickName) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getNickName, nickName);
        return count(queryWrapper) > 0;//相当于select count
    }

    private boolean emailExist(String email) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getEmail, email);
        return count(queryWrapper) > 0;//相当于select count
    }
}

